import { toFail, toSuccess, useEntityManager, useRedis } from "@sker/core";
import { useData } from "@sker/runtime";
import { RedisClientType } from "redis";
import { z } from "zod";

import { KsAccount } from "@sker/entities";
import axios from "axios";
import dayjs from "dayjs";
import request from 'superagent';
require('superagent-proxy')(request)
function toJson(res, set = new Set()) {
    if (!res) return;
    if (typeof res !== 'object') {
        return;
    }
    if (set.has(res)) {
        return;
    }
    set.add(res);
    const obj: any = {}
    Object.keys(res).map(key => {
        const val = res[key];
        if (typeof val === 'function') {
            return;
        } else if (typeof val === 'string') {
            obj[key] = val;
        } else if (typeof val === 'object') {
            obj[key] = toJson(val, set)
        }
    })
    return obj;
}

function get(targetUrl: string, ipJson: any) {
    return new Promise<string>((resolve, reject) => {
        const { ip, port, user, pass } = ipJson;
        const proxyServer = `${user}:${pass}@${ip}:${port}`
        const proxyUrl = `http://${proxyServer}`;
        (request as any).get(targetUrl)
            .proxy(proxyUrl)
            .then(res => {
                resolve(res.request.url);
            }).catch(err => {
                reject(err);
            });
    })
}

export default async () => {
    const input = z.object({
        url: z.string(),
        name: z.optional(z.string())
    });
    const body = input.parse(useData())
    let result: any;
    if (body.name) {
        const ksAccount = await useEntityManager(async m => {
            const list = await m.find(KsAccount, { where: { name: body.name } })
            if (list.length === 0) {
                return list[0]
            }
        })
        if (ksAccount) {
            return toSuccess({
                userId: ksAccount.user_id,
                ksid: ksAccount.ksid
            })
        }
    }
    async function getRealLink(link: string) {
        try {
            const response = await axios.get(link)
            const [path, query] = response.request.path.split(`?`)
            const res = path.match(/fw\/live\/(.*)/)
            if (res && res.length > 0) {
                const [, ksid] = res;
                const params: any = {}
                query.split('&').map(key => {
                    const [name, value] = key.split('=');
                    params[name] = value;
                });
                return { ...params, ksid };
            }
        } catch (e) {
            return;
        }
    }
    const call = async (r: RedisClientType) => {
        // 尝试用本机ip解析
        result = await getRealLink(body.url)
        if(result) return toSuccess(result);
        let ipJson = await getCacheIp(r);
        if (!ipJson) {
            ipJson = await getCacheIp(r);
            return;
        }
        try {
            const url = await get(body.url, ipJson)
            const [path, query] = url.split(`?`)
            const res = path.match(/fw\/live\/(.*)/)
            if (res && res.length > 0) {
                const [, ksid] = res;
                const params: any = {}
                query.split('&').map(key => {
                    const [name, value] = key.split('=');
                    params[name] = value;
                });
                result = { ...params, ksid };
            }
        } catch (e) {
            console.error(e)
        }
    }
    await useRedis(4, async r => {
        await call(r)
    })
    if (result) {
        return toSuccess(result)
    } else {
        return toFail(`获取失败`)
    }
}

async function getCacheIp(r: RedisClientType) {
    const ipKeys = await r.keys('ip_*')
    if (ipKeys && ipKeys.length > 0) {
        const key = ipKeys[0];
        const ipStr = await r.get(key);
        const ipJson = JSON.parse(ipStr);
        return ipJson;
    }
    try {
        return await getIp(r)
    } catch (e) {
        console.error(e.message)
    }
}
async function getIp(r: RedisClientType) {
    // http://sd.jghttp.alicloudecs.com/get_ip?num=1&type=2&pro=&city=0&yys=0&port=2&time=6&ts=1&ys=1&cs=1&lb=1&sb=0&pb=4&mr=2&regions=
    // http://sd.jghttp.alicloudecs.com/get_ip?num=1&type=2&pro=&city=0&yys=0&port=1&time=7&ts=1&ys=1&cs=1&lb=1&sb=0&pb=4&mr=1&regions=
    const url = `http://sd.jghttp.alicloudecs.com/get_ip?num=1&type=2&pro=&city=0&yys=0&port=1&time=6&ts=1&ys=1&cs=1&lb=1&sb=0&pb=4&mr=1&regions=`
    const data = await axios.get(url).then(res => res.data)
    if (data.code === 0) {
        const ips: any[] = data.data
        if (ips && ips.length > 0) {
            await Promise.all(ips.map(async ip => {
                console.log(ip)
                const key = `ip_${ip.ip}`
                await r.set(key, JSON.stringify(ip));
                const exip = Math.floor((dayjs(ip.expire_time, 'YYYY-MM-DD HH:mm:ss').toDate().getTime() - dayjs().toDate().getTime()) / 1000);
                await r.expire(key, exip)
            }));
            return ips[0];
        }
    }
}